#include "LayerListModel.h"
#include "ItemModel.h"

#include "LeIpc2581/enumtranslator.h"
#include "LeIpc2581/Layer.h"
#include "LeIpc2581/Set.h"

#include <QDebug>
#include <QHash>
#include <QSet>

struct LayerItem
{
    LayerItem():
        layer(nullptr)
    {}

    explicit LayerItem(const Ipc2581b::Layer *layer):
        layer(layer)
    {}

    QStringList specificationKeys() const
    {
        QStringList result;
        for (auto ref: layer->specRefList)
            result.append(ref->id);
        return result;
    }

    const Ipc2581b::Layer *layer;
    QList<const Ipc2581b::Set*> featureSetList;
};

class LayerListModelPrivate
{
    Q_DISABLE_COPY(LayerListModelPrivate)
    Q_DECLARE_PUBLIC(LayerListModel)
    LayerListModel * const q_ptr;

    explicit LayerListModelPrivate(LayerListModel *model):
        q_ptr(model)
    {}

    QList<LayerItem> m_data;
    QHash<QString, int> m_layerNametoRowNumber;

    inline void clear()
    {
        m_data.clear();
    }
};

LayerListModel::LayerListModel(QObject *parent):
    QAbstractTableModel(parent),
    d_ptr(new LayerListModelPrivate(this))
{
}

LayerListModel::~LayerListModel()
{

}

void LayerListModel::addLayer(const Ipc2581b::Layer *layer)
{
    Q_D(LayerListModel);
    d->m_data.append(LayerItem(layer));
    d->m_layerNametoRowNumber.insert(layer->name, d->m_data.count() - 1);
}

void LayerListModel::addFeatureSet(const QString &layerName, const Ipc2581b::Set *set)
{
    Q_D(LayerListModel);
    int row = d->m_layerNametoRowNumber.value(layerName, -1);
    if (row < 0)
        return;
    d->m_data[row].featureSetList.append(set);
}

const Ipc2581b::Layer *LayerListModel::layer(const QString &name) const
{
    Q_D(const LayerListModel);
    int row = d->m_layerNametoRowNumber.value(name, -1);
    if (row < 0)
        return nullptr;
    return d->m_data.value(row).layer;
}

const Ipc2581b::Layer *LayerListModel::layer(int row) const
{
    Q_D(const LayerListModel);
    if (row >= 0 && row < rowCount())
        return d->m_data.value(row).layer;
    return nullptr;
}

QList<const Ipc2581b::Layer *> LayerListModel::layers() const
{
    Q_D(const LayerListModel);
    QList<const Ipc2581b::Layer *> result;
    for (int row = 0; row < rowCount(); row++)
        result << d->m_data.value(row).layer;
    return result;
}

QList<const Ipc2581b::Set *> LayerListModel::featureSetList(int row)
{
    Q_D(const LayerListModel);
    if (row < 0 || row >= rowCount())
        return QList<const Ipc2581b::Set *>();
    return d->m_data.value(row).featureSetList;
}

void LayerListModel::clear()
{
    Q_D(LayerListModel);

    beginResetModel();
    d->clear();
    endResetModel();
}

QVariant LayerListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation != Qt::Horizontal)
        return QVariant();

    if (role != Qt::DisplayRole)
        return QVariant();

    switch (section)
    {
        case NameColumn:
            return "Name";
        case FunctionColumn:
            return "Function";
        case SideColumn:
            return "Side";
        case PolarityColumn:
            return "Polarity";
        default:
            return QVariant();
    }
}

int LayerListModel::rowCount(const QModelIndex &parent) const
{
    Q_D(const LayerListModel);

    if (parent.isValid())
        return 0;

    return d->m_data.count();
}

int LayerListModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;

    return ColumnCount;
}

QVariant LayerListModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    if (index.row() < 0 || index.row() >= rowCount())
        return QVariant();

    Q_D(const LayerListModel);
    const LayerItem item = d->m_data.value(index.row());
    const Ipc2581b::Layer *layer = item.layer;

    switch (role)
    {
        case Qt::DisplayRole:
            switch (index.column())
            {
                case NameColumn:
                    return layer->name;
                case FunctionColumn:
                    return Ipc2581b::EnumTranslator::layerFunctionText(layer->layerFunction);
                case SideColumn:
                    return Ipc2581b::EnumTranslator::sideText(layer->side);
                case PolarityColumn:
                    return Ipc2581b::EnumTranslator::polarityText(layer->polarity);
                default:
                    return QVariant();
            }
        case Qt::EditRole:
            switch (index.column())
            {
                case NameColumn:
                    return layer->name;
                case FunctionColumn:
                    return QVariant::fromValue<Ipc2581b::LayerFunction>(layer->layerFunction);
                case SideColumn:
                    return QVariant::fromValue<Ipc2581b::Side>(layer->side);
                case PolarityColumn:
                    return QVariant::fromValue<Ipc2581b::Polarity>(layer->polarity);
                default:
                    return QVariant();
            }
        case ItemModel::SpecificationModelRole:
            if (item.specificationKeys().isEmpty())
                return QVariant();
            return item.specificationKeys();
        default:
            return QVariant();
    }
}
